package xhttp

import (
	"encoding/json"
	"fmt"
	"gitee.com/go-mid/infra/xstruct"
	"net/http"
	"net/url"
	"reflect"
	"time"
)

var defaultClient = NewHttpClientWrapper(
	&http.Client{
		Transport: &http.Transport{
			MaxIdleConnsPerHost: 128,
			MaxConnsPerHost:     1024,
		},
		Timeout: 0,
	})

func HttpReqGetOk(url string, timeout time.Duration) ([]byte, error) {
	return defaultClient.HttpReqGetOk(url, timeout)
}

func HttpReqPostOk(url string, data []byte, timeout time.Duration) ([]byte, error) {
	return defaultClient.HttpReqPostOk(url, data, timeout)
}

func HttpReqOk(url, method string, data []byte, timeout time.Duration) ([]byte, error) {
	return defaultClient.HttpReqOk(url, method, data, timeout)
}

func HttpReqPost(url string, data []byte, timeout time.Duration) ([]byte, int, error) {
	return defaultClient.HttpReqPost(url, data, timeout)
}

func HttpReq(url, method string, data []byte, timeout time.Duration) ([]byte, int, error) {
	return defaultClient.HttpReq(url, method, data, timeout)
}

func HttpReqWithHeadOk(url, method string, heads map[string]string, data []byte, timeout time.Duration) ([]byte, error) {
	return defaultClient.HttpReqWithHeadOk(url, method, heads, data, timeout)
}

func HttpReqWithHead(url, method string, heads map[string]string, data []byte, timeout time.Duration) ([]byte, int, error) {
	return defaultClient.HttpReqWithHead(url, method, heads, data, timeout)
}
func httpContentTypeReqWithHead(url, method, contentType string, heads map[string]string, data []byte, timeout time.Duration) ([]byte, int, error) {
	if heads == nil {
		heads = make(map[string]string)
	}
	var contypKey = "Content-Type"
	if _, ok := heads[contypKey]; !ok {
		heads[contypKey] = contentType
	}
	return defaultClient.HttpReqWithHead(url, method, heads, data, timeout)
}
func HttpJsonReqWithHead(url, method string, heads map[string]string, data []byte, timeout time.Duration) ([]byte, int, error) {
	return httpContentTypeReqWithHead(url, method, "application/json", heads, data, timeout)
}
func HttpFormReqWithHead(url, method string, heads map[string]string, data []byte, timeout time.Duration) ([]byte, int, error) {
	return httpContentTypeReqWithHead(url, method, "application/x-www-form-urlencoded", heads, data, timeout)
}

//将对象转成form表单提交的请求体。 对象的简单属性直接转成字符串，复杂属性（指针、结构体、数组、slice等）会通过json序列化成字符串
//会将对象的 tag为form或者json的属性作为参数
//如果需要忽略的key，则form或structs是"-"会忽略
// 没有form 也没有json 则会默认使用属性名称
func BuildFormBody(o interface{}) ([]byte, error) {
	var form = make(url.Values)
	oStr := xstruct.New(o)
	for _, field := range oStr.Fields() {
		formKey, opts := field.Tag("form")
		if formKey == "-" {
			continue
		}
		if formKey == "" {
			formKey, opts = field.Tag("json")
		}
		if formKey == "" {
			formKey = field.Name()
		}
		if opts.Has("omitempty") && field.IsZero() {
			continue
		}
		var val string
		//如果是复杂类型，则转成json字符串，否则将结果直接转成字符串
		switch field.Kind() {
		case reflect.Interface, reflect.Struct, reflect.Map, reflect.Slice, reflect.Array, reflect.Ptr:
			d, err := json.Marshal(field.Value())
			if err != nil {
				return nil, err
			}
			val = string(d)
		default:
			val = fmt.Sprintf("%v", field.Value())
		}
		form.Add(formKey, val)
	}
	return []byte(form.Encode()), nil
}
